/******************************************************************************
 * Copyright (C) 2025 EternalChip, Inc.(Gmbh) or its affiliates.
 * 
 * All Rights Reserved.
 * 
 * @file bsp_mpuxxx_driver.h
 * 
 * @par dependencies 
 * 
 * - stdint.h
 * - stdio.h
 * - stdbool.h
 * 
 * @author aether
 * 
 * @brief Provide the HAL APIs of MPU6050 and corresponding options.
 * 
 * Processing flow:
 * 
 * call directly.
 * 
 * @version V1.0 2025-10-20
 *
 * @note 1 tab == 4 spaces!
 * 
 *****************************************************************************/
#ifndef __BSP_MPUXXX_DRIVER_H__
#define __BSP_MPUXXX_DRIVER_H__
//******************************** Includes *********************************//
#include "stdio.h"
#include "stdint.h"
#include "stdbool.h"

//******************************** Defines **********************************//
#define RTOS_SUPPORTING

//******************************** Declaring ********************************//

/*   Return values from functions    */
typedef enum
{ 
    MPUxxx_OK             = 0,          /*Operation completed successfully   */
    MPUxxx_ERROR          = 1,          /*Run-time error without case matched*/
    MPUxxx_ERRORTIMEOUT   = 2,          /*Operation failed with timeout      */
    MPUxxx_ERRORRESOURCE  = 3,          /*Resource not available             */
    MPUxxx_ERRORPARAMETER = 4,          /*Parameter error                    */
    MPUxxx_ERRORNOMEMORY  = 5,          /*Out of memory                      */
    MPUxxx_ERRORISR       = 6,          /*Not allowed in ISR context         */
    MPUxxx_RESERVED       = 0x7FFFFFFF, /*Reserved                           */
} mpuxxx_status_t;

/* From HAL Layer :       HAL_IIC    */
typedef struct
{  
    void *hi2c;     /* hi2c pointer to a I2C_HandleTypeDef structure */
    mpuxxx_status_t (*pf_iic_init)      (void *);   /* Initialize IIC   */
    mpuxxx_status_t (*pf_iic_deinit)    (void *);   /* Deinitialize IIC */

    /* Write an amount of data by IIC */
    mpuxxx_status_t (*pf_iic_mem_write)(void *hi2c,
                                        uint16_t dst_address, 
                                        uint16_t mem_addr, 
                                        uint16_t mem_size, 
                                        uint8_t  *p_data, 
                                        uint16_t size, 
                                        uint32_t timeout);
    /* Read an amount of data by IIC */
    mpuxxx_status_t (*pf_iic_mem_read) (void *hi2c, 
                                        uint16_t dst_address, 
                                        uint16_t mem_addr, 
                                        uint16_t mem_size, 
                                        uint8_t  *p_data, 
                                        uint16_t size, 
                                        uint32_t timeout);
    /* Read an amount of data by DMA from IIC driver */                                    
    mpuxxx_status_t (*pf_iic_mem_read_dma) 
                                       (void *hi2c, 
                                        uint16_t dst_address, 
                                        uint16_t mem_addr, 
                                        uint16_t mem_size, 
                                        uint8_t  *p_data, 
                                        uint16_t size );
} iic_driver_interface_t;

/* Interrupt of hardware */
typedef struct
{
    int8_t (*pfinit)(void);             /* Initial interrupt */
    int8_t (*pfdeinit)(void);           /* Deinitial interrupt */
    int8_t (*pfenableInterrupt)(void);  /* Enable interrupt */
    int8_t (*pfdisableInterrupt)(void); /* Disable interrupt */
    int8_t (*pfenableClock)(void);      /* Enable interrupt clock */
    int8_t (*pfdisableClock)(void);     /* Disable interrupt clock */
    /* Mpu interrupt callback */
    int8_t (*pfintcallback)(void *(pfcallback_after_data_available)(void));
}interruption_interface_t;

/* From core layer */
typedef struct
{
    uint32_t (*pfget_tick_count)(void);
}timebase_interface_t;

/* Store data from mpuxxx driver     */
typedef struct
{
    int8_t (*pfbuffer_init)(uint8_t size);  /* Init mpuxxx buffer */
    uint8_t *(*pfget_rbuffer_addr) (void);  /* Get read buffer    */
    uint8_t *(*pfget_wbuffer_addr) (void);  /* Get write buffer   */
}buffer_interface_t;

/* Delay function */
typedef struct
{
    void (*pf_delay_init) (void);               /* Delay init interface    */
    void (*pf_delay_us) (const uint32_t);       /* Delay us interface      */
    void (*pf_delay_ms) (const uint32_t);       /* Delay ms interface      */
} delay_interface_t;


/* From OS Layer */
#ifdef RTOS_SUPPORTING
typedef struct
{
    void (*pf_rtos_yield) (const uint32_t);         /* OS No-Blocking delay  */
} yield_interface_t;

typedef struct
{
    /* Create a queue */
    mpuxxx_status_t (*os_queue_create)(uint32_t const item_num, 
                                    uint32_t const item_size, 
                                    void ** const queue_handle);
    /* Put data in queue */
    mpuxxx_status_t (*os_queue_put)(void * const queue_handle,
                                    void * const item, 
                                    uint32_t const timeout);
    /* Put data in queue using in interrupt */
	mpuxxx_status_t (*os_queue_put_isr)(
                                    void * const queue_handle,
									void * const item, 
									long * const HigherPriorityTaskWoken);
    /* Get data from queue */
    mpuxxx_status_t (*os_queue_get)(void * const queue_handle,
                                    void * const item, 
                                    uint32_t const timeout);
    /* delete date from queue */
    mpuxxx_status_t (*os_queue_delete)(void * const queue_handle);

    /* Create a mutex */
    mpuxxx_status_t (*os_semaphore_create_mutex) (void **mutex_handle);
    /* Delete mutex */
    mpuxxx_status_t (*os_semaphore_delete_mutex) (void * const mutex_handle);
    /* Lock mutex */
    mpuxxx_status_t (*os_semaphore_lock_mutex)   (void * const mutex_handle);
    /* Unlock mutex */
    mpuxxx_status_t (*os_semaphore_unlock_mutex) (void * const mutex_handle);

    /* Create a binary */
    mpuxxx_status_t (*os_semaphore_create_binary) (void **binary_handle);
    /* Delete binary */
    mpuxxx_status_t (*os_semaphore_delete_binary) (void * const binary_handle);
    /* Wait for binary */
    mpuxxx_status_t (*os_semaphore_wait_binary)   (void * const binary_handle);
    /* Send binary */
    mpuxxx_status_t (*os_semaphore_signal_binary) (void * const binary_handle);
    /* Send binary using in interrupt */
	mpuxxx_status_t (*os_semaphore_signal_binary_isr)(
                                        void * const binary_handle,
                                       long * const HigherPriorityTaskWoken);
    /* Send notify using in interrupt */
	mpuxxx_status_t (*os_semaphore_signal_notify_isr)(
                                        void * const notify_handle, 
                                        uint32_t ulValue, 
                                        uint32_t eAction, 
                                        long * const HigherPriorityTaskWoken);
    /* Wait for notify */
    mpuxxx_status_t (*os_semaphore_wait_notify)( 
                                            uint32_t ulBitsToClearOnEntry, 
                                            uint32_t ulBitsToClearOnExit, 
                                            uint32_t *pulNotificationValue, 
                                            uint32_t timeout);
} os_interface_t;
#endif /* End of RTOS_SUPPORTING       */

/* mpu6050 data format */
typedef struct
{
    /* Raw accelerometer data from sensor */
    int16_t accel_x_raw;
    int16_t accel_y_raw;
    int16_t accel_z_raw;

    /* Processed accelerometer data in g units */
    double ax;
    double ay;
    double az;

    /* Raw gyroscope data from sensor */
    int16_t gyro_x_raw;
    int16_t gyro_y_raw;
    int16_t gyro_z_raw;

    /* Processed gyroscope data in degrees/s */
    double gx;
    double gy;
    double gz;

    /* Temperature reading in degrees Celsius */
    float temperature;

    /* Kalman filter processed angles */
    double kalman_angle_x;
    double kalman_angle_y;
} mpuxxx_data_t;


/*     Driver structure              */
typedef struct bsp_mpuxxx_driver
{
    /* Core Layer */
    iic_driver_interface_t          *p_iic_driver_interface;
    interruption_interface_t        *p_interrupt_interface;
    delay_interface_t               *p_delay_interface;
    timebase_interface_t            *p_timebase_interface;

    /* OS Layer  */
#ifdef RTOS_SUPPORTING
    yield_interface_t  *p_yield_interface;
    os_interface_t     *p_os_interface;
    buffer_interface_t *p_buffer_interface;

    void *queue_handle;
    void *semaphore_mutex_handle;
    void *semaphore_binary_handle;
    void *notify_handle;
#endif /* End of OS_SUPPORTING */
    
    void (*pf_dma_completed_callback)(void);
    void (*pf_int_interrupt_callback)(void);

    /* Interface of mpuxxx driver    */
    mpuxxx_status_t (*pf_init)                (struct bsp_mpuxxx_driver *);
    mpuxxx_status_t (*pf_deinit)              (struct bsp_mpuxxx_driver *);
    mpuxxx_status_t (*pf_sleep)               (struct bsp_mpuxxx_driver *);
    mpuxxx_status_t (*pf_wakeup)              (struct bsp_mpuxxx_driver *);
    mpuxxx_status_t (*pf_set_gyro_fsr)        (struct bsp_mpuxxx_driver *, uint8_t);
    mpuxxx_status_t (*pf_set_accel_fsr)       (struct bsp_mpuxxx_driver *, uint8_t);
    mpuxxx_status_t (*pf_set_lpf)             (struct bsp_mpuxxx_driver *, uint8_t);
    mpuxxx_status_t (*pf_set_rate)            (struct bsp_mpuxxx_driver *, uint8_t);
    mpuxxx_status_t (*pf_set_interrupt_enable)(struct bsp_mpuxxx_driver *, uint8_t);
    mpuxxx_status_t (*pf_set_motion_threshold)(struct bsp_mpuxxx_driver *, uint8_t);
    mpuxxx_status_t (*pf_set_INT_level)       (struct bsp_mpuxxx_driver *, uint8_t);
    mpuxxx_status_t (*pf_set_user_ctrl)       (struct bsp_mpuxxx_driver *, uint8_t);
    mpuxxx_status_t (*pf_set_pwr_mgmt1_reg)   (struct bsp_mpuxxx_driver *, uint8_t);
    mpuxxx_status_t (*pf_set_pwr_mgmt2_reg)   (struct bsp_mpuxxx_driver *, uint8_t);
    mpuxxx_status_t (*pf_set_fifo_en_reg)     (struct bsp_mpuxxx_driver *, uint8_t);    
    mpuxxx_status_t (*pf_get_temperature)     (struct bsp_mpuxxx_driver *, mpuxxx_data_t *);
    mpuxxx_status_t (*pf_get_accel)           (struct bsp_mpuxxx_driver *, mpuxxx_data_t *);
    mpuxxx_status_t (*pf_get_gyro)            (struct bsp_mpuxxx_driver *, mpuxxx_data_t *);
    mpuxxx_status_t (*pf_get_all_data)        (struct bsp_mpuxxx_driver *, mpuxxx_data_t *);
    mpuxxx_status_t (*pf_get_interrupt_status_reg)(struct bsp_mpuxxx_driver *, uint8_t *);
    mpuxxx_status_t (*pf_read_fifo_packet)    (struct bsp_mpuxxx_driver *p_mpu_driver, 
                                                                           mpuxxx_data_t *p_data);
    mpuxxx_status_t (*pf_read_fifo_isr_occur) (struct bsp_mpuxxx_driver *p_mpu_driver, 
                                                                           mpuxxx_data_t *p_data);
} bsp_mpuxxx_driver_t;

//******************************** Functions ********************************//
/** 
 * @brief Initialize the MPU6050 driver instance with the provided interfaces 
 *        and callbacks
 * 
 * @param p_mpuxxx_driver Pointer to the MPU6050 driver structure to initialize
 * @param p_iic_driver_interface Pointer to the IIC driver interface implementation
 * @param p_yield_interface      Pointer to the yield interface (OS mode only)
 * @param p_os_interfece         Pointer to the OS interface (OS mode only) 
 * @param p_timebase_interface   Pointer to the timebase interface
 * @param callback_register      Function to register interrupt callback
 * @param callback_register_dma  Function to register DMA callback
 * @param queue_handle           Handle to queue for data transfer (OS mode only)
 * 
 * @return MPU6050_OK if successful, error code otherwise
 * 
*/
mpuxxx_status_t bsp_mpuxxx_driver_inst(
                bsp_mpuxxx_driver_t    *p_mpuxxx_driver,
                iic_driver_interface_t *p_iic_driver_interface,
#ifdef RTOS_SUPPORTING
                yield_interface_t      *p_yield_interface,
                os_interface_t         *p_os_interfece,
#endif /* End of OS_SUPPORTING */
                delay_interface_t      *p_delay_interface,
                timebase_interface_t   *p_timebase_interface,
                void (*callback_register)    (void (*callback)(void *, void *)),
                void (*callback_register_dma)(void (*callback)(void *, void *))
#ifdef RTOS_SUPPORTING
                ,void *queue_handle,
                void *semaphore_handle,
                void *notify_handle
#endif /* End of OS_SUPPORTING */
                                                                            );



#endif /* End of __BSP_MPUXXX_DRIVER_H__ */